import java.util.ArrayList;
import java.util.Arrays;


public class urp {
	private ArrayList<cube> cubelist;
	private int c; // cube number
	private int v; // variable number
//	private int[] binate; // the number of binate value
//	private int[] pos;
//	private int[] neg;
//	private int[] appear;
	private static class cube {
		int[] var;
		public cube(int[] readin) {
			var = readin;
		}
		
		public boolean dc() {
			boolean isDC = true;
			for (int i = 0; i < var.length; i++)
				if ( var[i] != 0) { 
					isDC = false;
					break;
				}
			return isDC;
		}
	};
	
	
	public urp(int vNumber, int cNumber) {
		cubelist = new ArrayList<cube>();
		this.c = cNumber;
		this.v = vNumber;
//		this.binate = new int[vNumber];
//		this.pos = new int[vNumber];
//		this.neg = new int[vNumber];
//		this.appear = new int[vNumber];
//		Arrays.fill(binate, -1);
	}
	
	public void add(cube newcube) {
		this.cubelist.add(newcube);
	}
	
//	public void posAdd(int index) {
//		this.binate[index] ++;
//	}
//	
//	public void negAdd(int index) {
//		this.binate[index] --;
//	}
	
	public int isEasy(ArrayList<cube> list) {
		if (list.isEmpty()) return 0; // 0 represents empty
		if (containDC(list)) return 1; // 1 represents it has a don't care cube
 		if (list.size() == 1) return 2; //2 represents it only has one cube
		return 3; // 3 represents it's not easy
	}
	
	public boolean containDC(ArrayList<cube> list) {
		boolean isDC = false;
		for (cube n: list) {
			if (n.dc()) { isDC = true; break;}
		}
		
		return isDC;	
	}
	
	public ArrayList<cube> complement(ArrayList<cube> list) {
		ArrayList<cube> newCubeList = new ArrayList<cube>();
		if (isEasy(list) == 0) {
			int[] tmpArray = new int[this.v];
			Arrays.fill(tmpArray, 0);
			cube node = new cube(tmpArray);
			newCubeList.add(node);
		}
		else if (isEasy(list) == 1) return new ArrayList<cube>();
		else if (isEasy(list) == 2) {
			int[] tmpArray = new  int[this.v];
			cube node = list.get(0);
			for (int i = 0; i < this.v; i++){
				tmpArray = new int[this.v];
				if (node.var[i] == 1) {
					tmpArray[i] = 10;
					cube tmpNode = new cube(tmpArray);
					newCubeList.add(tmpNode);
				}
				if (node.var[i] == 10) {
					tmpArray[i] = 1;
					cube tmpNode = new cube(tmpArray);
					newCubeList.add(tmpNode);
				}
			}
			return newCubeList;
		}
		else {
			int mostBinate = mostBinate(list);
			ArrayList<cube> Plist = complement(posCofactor(list, mostBinate));
			ArrayList<cube> Nlist = complement(negCofactor(list, mostBinate));
			Plist = AND(Plist,mostBinate,true);
			Nlist = AND(Nlist,mostBinate,false);
			newCubeList.addAll(Plist);
			newCubeList.addAll(Nlist);
		}
		return newCubeList;	
	}
	
	public ArrayList<cube> AND( ArrayList<cube> list, int index, boolean sign) {
		ArrayList<cube> newList = new ArrayList<cube>();
		int [] tmp;
		cube tmpNode;
		for (cube node: list){
			tmp = new int[this.v];
			for (int i = 0; i < this.v; i++) tmp[i] = node.var[i];
			if (sign) tmp[index] = 1;
			else tmp[index] = 10;
			tmpNode = new cube(tmp);
			newList.add(tmpNode);
		}
		return newList;
	}
	
	public ArrayList<cube> posCofactor(ArrayList<cube> list, int index) {
		ArrayList<cube> newList = new ArrayList<cube>();
		int [] tmp;
		cube tmpNode;
		for (cube node: list) { 
			if (node.var[index] == 0) {
				tmp = new int[this.v];
				for (int i = 0; i < this.v; i++) tmp[i] = node.var[i];
				tmpNode = new cube(tmp);
				newList.add(tmpNode);
			}
			else if (node.var[index] == 1) {
				tmp = new int[this.v];
				for (int i = 0; i < this.v; i++) tmp[i] = node.var[i];
				tmp[index] = 0;
				tmpNode = new cube(tmp);
				newList.add(tmpNode);
			}
		}
		return newList;
	}
	
	public ArrayList<cube> negCofactor(ArrayList<cube> list, int index) {
		ArrayList<cube> newList = new ArrayList<cube>();
		int [] tmp;
		cube tmpNode; 
		for (cube node: list) {
			if (node.var[index] == 0) {
				tmp = new int[this.v];
				for (int i = 0; i < this.v; i++) tmp[i] = node.var[i];
				tmp[index] = 0;
				tmpNode = new cube(tmp);
				newList.add(node);
			}
			else if (node.var[index] == 10) {
				tmp = new int[this.v];
				for (int i = 0; i < this.v; i++) tmp[i] = node.var[i];
				tmp[index] = 0;
				tmpNode = new cube(tmp);
				newList.add(tmpNode);
			}
		}
		return newList;
	}
	
	private class urpInfo {
		private int[] binate;
		private int[] pos;
		private int[] neg;
		private int[] appear;
		boolean unate;
		
		public urpInfo(int vNumber){
			this.binate = new int[vNumber];
			this.pos = new int[vNumber];
			this.neg = new int[vNumber];
			this.appear = new int[vNumber];
			this.unate = false;
		}
	};
	
	public urpInfo computeAppear(ArrayList<cube> list) {
		urpInfo info = new urpInfo(this.v);
		boolean check = false;
		for (cube p: list) {
			for (int i = 0; i < this.v; i++) {
				if (p.var[i] == 1) info.pos[i] ++;
				if (p.var[i] == 10) info.neg[i] ++;
			}
		}
		
		for (int i=0; i < this.v; i++) {
			if (info.pos[i] != 0 && info.neg[i] != 0) check = true;
			info.binate[i] = Math.abs(info.pos[i] - info.neg[i]);
			info.appear[i] = info.pos[i] + info.neg[i];
		}
		if (!check) info.unate = true;
		return info;
	}
	
	public int mostBinate(ArrayList<cube> list) {
		int index = 0;
		int value = 0;
		int tmp   = 0;
		urpInfo info = computeAppear(list);
		Queue<Integer> qs = new Queue<Integer>();
		if (info.unate) {
			for (int i = 0; i < this.v; i++) {
				if (info.appear[i] == 0) continue; 
				if (info.pos[i] != 0) {
					tmp = info.pos[i];
					if (tmp > value) { index = i;}
				}
				else {
					tmp = info.neg[i];
					if (tmp > value) { index = i;}
				}
			}
		}
		else {
			for (int i = 0; i < this.v; i++) {
				tmp = info.appear[i]; 
				if ( tmp > value) {
					value = tmp;
					qs = new Queue<Integer>();
					qs.enqueue(i);
					index = i;
				}
				else if (tmp == value) qs.enqueue(i);
			}
			
			if (qs.size() == 1) return qs.dequeue();
			else {
				value = info.binate[index];
				for (Integer p:qs) {
					tmp = info.binate[p];
					if (value > tmp ) {
						value = tmp;
						index = p;
					}
				}
			}
		}
		return index;
	}
	
	
	public static void main(String[] args) {
		String filename = args[0];
		In in = new In(filename);
		urp test = new urp(in.readInt(), in.readInt());
		
		int ndc;
		StdOut.println(test.c + " " + test.v);
		int[] cubeValue;
		
//		int[] pos = new int[test.v];
//		int[] neg = new int[test.v];
		for (int i = 0; i < test.c; i++) {
			ndc = in.readInt();
			cubeValue = new int[test.v];
			for (int j = 0; j < ndc; j++) {
				int index = in.readInt();
				if (index > 0) {
					cubeValue[index - 1] = 1;
//					test.pos[index - 1]++;
				}
				else {
					cubeValue[Math.abs(index) -1] = 10;
//					test.neg[Math.abs(index) - 1]++;
				}
			}
			cube cu = new cube(cubeValue);
			test.add(cu);	
		}
		
//		for (int i = 0; i < test.v; i++) {
//			test.appear[i] = test.pos[i] + test.neg[i];
//			test.binate[i] = Math.abs(test.pos[i] - test.neg[i]);
//		}
		
//		for (cube p: test.cubelist) {
//			String output  = "";
//			for(int i = 0; i < p.var.length; i++)
//				output = output + " " + p.var[i];
//			StdOut.println( output);
//		}
		
//		ArrayList<cube> tt = test.negCofactor(test.cubelist, 0);
		ArrayList<cube> result = test.complement(test.cubelist);
		String delim = "[.]";
		String[] tokens = filename.split(delim);
		String output = "";
		Out out = new Out(tokens[0] + "_complement.pcn");
		out.print(test.v + "\n");
		out.print(result.size() + "\n");
		for (cube p: result) {
			int count = 0;
			output = "";
			for (int i = 0; i < test.v; i++) {
				if (p.var[i] != 0) {
					count++;
					if (p.var[i] == 1) output = output + " " + (i + 1);
					else output = output + " -" + (i + 1);
				}
			}
			output = count + output + "\n";
			out.print(output);
			StdOut.print(output);
		}
		StdOut.print(result.size());
//		output = "";
//		for (int i = 0; i < test.v; i++) 
//			output = output + " " + test.binate[i] + "" ;
//		StdOut.println( output);
		
//		for (cube p: tt) {
//			String output  = "";
//			for(int i = 0; i < p.var.length; i++)
//				output = output + " " + p.var[i];
//			StdOut.println( output);
//		}
				
	}
	
}
